﻿using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage.Table.DataServices;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;
using System.Web;

namespace Wams.Admin.UI
{
    public class AuthToken:TableEntity
    {
        public DateTime LoginTimestamp;
        public AuthToken(string token)
        {
            PartitionKey = token;
            RowKey = "admin";
            LoginTimestamp = DateTime.UtcNow;
        }
        public AuthToken() { }

        public static string GetTableName()
        {
            return Utils.ContainerName + "uisessions";
        }
        public void Save()
        {
            CloudTableClient tableClient = Utils.StorageAccount.CreateCloudTableClient();

            CloudTable table = tableClient.GetTableReference(GetTableName());
            table.CreateIfNotExists();

            TableOperation retrieveOperation = TableOperation.Retrieve<AuthToken>(this.PartitionKey, this.RowKey);

            TableResult retrievedResult = table.Execute(retrieveOperation);

            AuthToken specificEntity = (AuthToken)retrievedResult.Result;
            TableOperation tOp = null;
            if (specificEntity != null)
            {
                specificEntity.ETag = "*";
                tOp = TableOperation.Replace(specificEntity); // Replace it without affecting custom fields, just to update the timestamp field.
            }
            else tOp = TableOperation.Insert(this);

            table.Execute(tOp);
        }

        public bool IsValid()
        {
            CloudTableClient tableClient = Utils.StorageAccount.CreateCloudTableClient();

            CloudTable table = tableClient.GetTableReference(GetTableName());
            table.CreateIfNotExists();

            TableOperation retrieveOperation = TableOperation.Retrieve<AuthToken>(this.PartitionKey, this.RowKey);

            TableResult retrievedResult = table.Execute(retrieveOperation);

            AuthToken specificEntity = (AuthToken)retrievedResult.Result;

            if (specificEntity == null) return false;
            if (DateTime.UtcNow.Subtract(specificEntity.Timestamp.DateTime).TotalMinutes > 20) return false;
            return true;
        }
    }

    [ServiceContract(Namespace = "")]
    [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Auth
    {
        public string AdminUser
        {
            get { return ConfigurationManager.AppSettings["Wams.UI.Username"]; }
        }
        public string AdminPass
        {
            get { return ConfigurationManager.AppSettings["Wams.UI.Password"]; }
        }

        // To use HTTP GET, add [WebGet] attribute. (Default ResponseFormat is WebMessageFormat.Json)
        // To create an operation that returns XML,
        //     add [WebGet(ResponseFormat=WebMessageFormat.Xml)],
        //     and include the following line in the operation body:
        //         WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
        [OperationContract]
        public bool Login(string username, string password)
        {
            if (string.IsNullOrEmpty(AdminUser)) return true;

            if (AdminUser.ToLower() != username.ToLower() || AdminPass != password) return false;

            AuthToken newToken = new AuthToken(Guid.NewGuid().ToString());
            newToken.Save();

            HttpCookie cookie = new HttpCookie("wamsUI.auth", newToken.PartitionKey);
            cookie.Expires = DateTime.Now.AddDays(7);
            HttpContext.Current.Response.Cookies.Add(cookie);
            return true;
        }

        [OperationContract]
        public bool CheckLogin()
        {
            HttpCookie authCookie = HttpContext.Current.Request.Cookies["wamsUI.auth"];
            if (authCookie == null || string.IsNullOrEmpty(authCookie.Value)) return false;
            if (!Auth.CheckToken(authCookie.Value, true)) return false;
            return true;
        }

        public static void ClearExpired()
        {
            CloudTableClient tableClient = Utils.StorageAccount.CreateCloudTableClient();

            CloudTable table = tableClient.GetTableReference(AuthToken.GetTableName());
            TableServiceContext tableServiceContext = table.ServiceClient.GetTableServiceContext();
            IQueryable<AuthToken> q = (from token in tableServiceContext.CreateQuery<AuthToken>(AuthToken.GetTableName())
                                           select token);

            foreach (AuthToken token in q)
            {
                if (token.Timestamp >= DateTime.UtcNow.AddMinutes(-20)) continue;
                token.ETag = "*";
                TableOperation deleteOp = TableOperation.Delete(token);
                table.Execute(deleteOp);
            }
        }
        public static bool CheckToken(string token, bool updateTimestamp)
        {
            if (string.IsNullOrEmpty(token)) return false;

            ClearExpired();

            AuthToken checkToken = new AuthToken(token);
            if (!checkToken.IsValid()) return false;
            if (updateTimestamp) checkToken.Save();
            return true;
        }
    }
}
